package auth

import (
	"demo/domain/model"
	"demo/infra/errors"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
)

// AuthMiddleware 认证中间件结构体（支持依赖注入，便于扩展）
type AuthMiddleware struct {
	// 可配置项（灵活调整行为）
	excludePaths []string // 无需验证的路径列表
	loginURL     string   // 登录页URL（未登录时重定向）
}

// Option 配置选项（函数式选项模式）
type Option func(*AuthMiddleware)

// NewAuthMiddleware 创建认证中间件实例
func NewAuthMiddleware(opts ...Option) *AuthMiddleware {
	m := &AuthMiddleware{
		excludePaths: []string{"/auth/loginPage", "/auth/registerPage", "/health", "/static"}, // 默认排除路径
		loginURL:     "/auth/loginPage",                                                       // 默认登录页
	}
	// 应用配置选项
	for _, opt := range opts {
		opt(m)
	}
	return m
}

// WithExcludePaths 自定义无需验证的路径
func WithExcludePaths(paths ...string) Option {
	return func(m *AuthMiddleware) {
		m.excludePaths = append(m.excludePaths, paths...)
	}
}

// WithLoginURL 自定义登录页URL
func WithLoginURL(url string) Option {
	return func(m *AuthMiddleware) {
		m.loginURL = url
	}
}

// RequiredLogin 核心中间件：验证登录状态
func (m *AuthMiddleware) RequiredLogin() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 1. 检查当前路径是否需要排除验证
		if m.shouldExclude(c.Request.URL.Path) {
			c.Next()
			return
		}

		// 2. 从会话获取用户信息
		user, err := GetCurrentUser(c.Request)
		if err != nil {
			// 会话获取失败（如Cookie解析错误）
			m.handleUnauthorized(c, errors.NewBizError("B0000", "会话验证失败，请重新登录"))
			return
		}

		// 3. 验证用户是否登录
		if user == nil || user.ID == 0 {
			m.handleUnauthorized(c, errors.NewBizError("B0000", "请先登录"))
			return
		}

		// 4. 验证会话有效性（可选：如检查用户是否被禁用）
		if err := m.validateUserStatus(user); err != nil {
			m.handleUnauthorized(c, err)
			return
		}

		// 5. 登录状态有效：将用户信息存入上下文，供后续处理器使用
		c.Set("current_user", user)
		// 延长会话有效期（活跃用户自动续期）
		_ = SetSession(c.Writer, c.Request, user)

		c.Next()
	}
}

// 检查路径是否需要排除验证
func (m *AuthMiddleware) shouldExclude(path string) bool {
	for _, p := range m.excludePaths {
		// 支持前缀匹配（如/static/* 排除所有静态资源）
		if strings.HasPrefix(path, p) {
			return true
		}
	}
	return false
}

// 处理未授权请求（根据请求类型返回不同响应）
func (m *AuthMiddleware) handleUnauthorized(c *gin.Context, err error) {
	// 记录未授权访问日志（便于排查）
	//c.Logger().Warnf("未授权访问: %s, 原因: %v", c.Request.URL.Path, err)

	// 根据请求头判断是API请求还是页面请求
	if strings.Contains(c.Request.Header.Get("Accept"), "application/json") {
		// API请求：返回JSON错误
		c.JSON(http.StatusUnauthorized, gin.H{
			"code":    http.StatusUnauthorized,
			"message": err.Error(),
			"login":   m.loginURL,
		})
	} else {
		// 页面请求：重定向到登录页，并携带原路径（登录后可跳转回来）
		redirectURL := m.loginURL + "?redirect=" + c.Request.URL.Path
		c.Redirect(http.StatusSeeOther, redirectURL)
	}
	c.Abort() // 终止后续处理
}

// 验证用户状态（可扩展：如检查用户是否被禁用、过期等）
func (m *AuthMiddleware) validateUserStatus(*model.UserSimple) error {
	// 示例：检查用户是否被标记为禁用（需在User实体中添加IsDisabled字段）
	// if user.IsDisabled {
	// 	return errors.New("账号已被禁用，请联系管理员")
	// }
	return nil
}

// GetCurrentContextUser 从上下文获取当前登录用户（简化处理器中获取用户的逻辑）
func GetCurrentContextUser(c *gin.Context) (*model.UserSimple, error) {
	user, exists := c.Get("current_user")
	if !exists {
		return nil, errors.NewBizError("B0000", "未获取到用户信息")
	}
	return user.(*model.UserSimple), nil
}
